from PySide6.QtWidgets import QDialog, QVBoxLayout, QFormLayout, QHBoxLayout, QLabel, QLineEdit, QPushButton, QMessageBox, \
    QApplication, QCheckBox, QGridLayout, QComboBox, QGroupBox, QPlainTextEdit, QWidget, QTreeWidget, QTreeWidgetItem
import sys

class Help_Window(QDialog):
    def __init__(self, window=None):
        super(Help_Window, self).__init__()
        self.window = window
        self.initset()

    def initset(self):
        self.setWindowTitle('帮助')
        # self.setWindowIcon(self.window.icon_logo)
        self.setModal(True)
        self.setMinimumHeight(450)
        self.setMinimumWidth(650)
        self.main_layout = QGridLayout(self)
        self.tree_view = QTreeWidget()
        self.tree_view.setColumnCount(1)
        self.tree_view.setHeaderLabels(['目录'])
        self.tree_view.clicked.connect(self.tree_clicked)
        self.text_edit = QPlainTextEdit()
        self.text_edit.setReadOnly(True)
        # self.text_edit.setDisabled(False)
        self.main_layout.addWidget(self.tree_view, 0, 0, 1, 2)
        self.main_layout.addWidget(self.text_edit, 0, 2, 1, 8)
        self.help_dict = {'菜单': {
            '文件': ['选择配置', '重新选择该配置', '导出配置头'],
            '清除记录': ['清除中心页面', '清空控制台'],
            '视图': ['参数配置-btn', '控制面板'],
            '管理': ['通讯配置', '重置TCP连接', '远程升级', '上线', '下线', '保存host'],
            'Scope': ['打开', '通道管理', '转换波形数据'],
            'E2PROM': [],
            '帮助': []
                    },
            '主界面': {'参数配置': [],
                    'Tab栏': [],
                    '控制台': ['按钮', '下拉列表', '输入列表']
                    },
            '状态栏': {'临时状态': [],
                    '固定状态': []
                    },
        }
        for i in range(len(self.help_dict)):
            tree_grandfathedr = QTreeWidgetItem(self.tree_view)
            tree_grandfathedr.setText(0, list(self.help_dict.keys())[i])
            for j in range(len(self.help_dict[list(self.help_dict.keys())[i]])):
                tree_father = QTreeWidgetItem(tree_grandfathedr)
                tree_father.setText(0, list(self.help_dict[list(self.help_dict.keys())[i]].keys())[j])
                for k in range(len(self.help_dict[list(self.help_dict.keys())[i]][list(self.help_dict[list(self.help_dict.keys())[i]].keys())[j]])):
                    tree_son = QTreeWidgetItem(tree_father)
                    tree_son.setText(0, self.help_dict[list(self.help_dict.keys())[i]][list(self.help_dict[list(self.help_dict.keys())[i]].keys())[j]][k])

        # self.tree_view.expandAll()

        # self.tree_peizhi = QTreeWidgetItem(self.tree_view)
        # self.tree_peizhi.setText(0, '配置')
        # self.tree_daoru = QTreeWidgetItem(self.tree_peizhi)
        # self.tree_daoru.setText(0, '导入文件详细')
        # self.tree_peizhiwenjian = QTreeWidgetItem(self.tree_peizhi)
        # self.tree_peizhiwenjian.setText(0, '配置文件详细')
        #
        # self.tree_zhujiemian = QTreeWidgetItem(self.tree_view)
        # self.tree_zhujiemian.setText(0, '主界面')

        # 文件详细
        self.help_dict_str = {}
        self.help_dict_str['选择配置'] = '''
一、通过选择配置选择配置文件(配置文件必需要有以下条目, (*)代表条目属性不能为空)
1、类型号:(*)
    举例: A0 (用于分类和区分相同参数名)
2、1级类型:(*)
    举例: 系统 (用于分类)
3、2级类型:(*)
    举例: 状态监视(用于分类)
4、参数名:(*)
    举例: 工作模式
5、参数名英:
    举例: _WorkMode(用于在导出下位机头文件时命名，例如 #define B0_WorkMode hostParas.u32[6] )
6、数据类型:
    (1)'1'/'3'/'5':为u32类型传输， 其他为f32类型传输
    (2)上位机上'3'和'5'为下拉选择输入框，'1'和其他为文本输入框
    (3)'3'和'5'类型需要有 '选择型操作定义'的支持，否则将会被视为默认f32类型
    (4)'3'类型的值对应'选择型操作定义'的实际数值，而'5'类型则是按位(bit)对应’选择型操作定义'的值
7、缺省值:
    (1)不写即为'0'
    (2)在e2prom模块有将值保存到配置文件的功能，可能会改变原来的值
8、最小值:
    用来限定输入时的最小值，不写即为'-∞'
9、最大值:
    用来限定输入时的最大值，不写即为'+∞'
10、单位:
    用于显示数值的单位，不写即视为没有单位
11、小数位数:
    只用于显示小数数值的小数位数，不写即视为保留两位小数，但在输入时仍会以最高精度去输入或保存
12、写权限:
    用于限定读写权限，'1'为读写参数，不写或其他即视为只读参数
13、日志输出:
    用于保存host数据的标志，写'1'即为保存，不写或其他即为不保存，上线之后点击保存host按钮将会把要保存的数据保存到以开始时间命名的日志文件内
14、EEPROM变量:
    用于区分在E2PROM模块显示并可以保存/读取e2prom的参数， 写'1'即为需要，不写或其他即为不需要保存的参数
15、选择型操作定义:
    (1)只有'数据类型'为'3'或'5'的参数写值才有用
    (2)举例: 0-初始化;1-上电检测;2-系统故障;3-开机封锁;4-开机准备;5-预充电;6-待机;7-预励磁;8-运行;9-OFF1停车;10-OFF3停车;(必须以'-'和';’分割，最后的字符';'可有可无)
    (3)数字字符可以略过，举例: 0-HMI;1-端子;3-远程上位机;
    (4)'3'类型的值对应'选择型操作定义'的实际数值，而'5'类型则是按位(bit)对应’选择型操作定义'的值
        '''
        self.help_dict_str['重新选择该配置'] = '''
1、用于重新加载上一次打开的配置文件(例如修改过配置文件后直接重新加载一遍)
2、打开程序时会自动加载上一次打开的配置文件，如果加载失败了就取消加载
                '''
        self.help_dict_str['导出配置头'] = '''
1、通过加载的配置文件，导出相对应的头文件
2、需要自定义导出的命名格式(前缀：地址)，':'是不可缺少的字符，且前缀可以省略
3、导出的定义为 #define 前缀+类型号+参数名英 地址.u32[i]/地址.f32[i]
                '''
        self.help_dict_str['清除中心页面'] = '''
用于清空Tab栏页面和Tab栏记录的按钮，不可恢复
                '''
        self.help_dict_str['清空控制台'] = '''
用于清空控制台页面控件和记录的按钮，不可恢复
                '''
        self.help_dict_str['参数配置-btn'] = '''
用于打开/关闭参数配置Dock(left)栏显示的按钮
                '''
        self.help_dict_str['控制面板'] = '''
用于打开/关闭控制面板Dock(down)栏显示的按钮
                '''
        self.help_dict_str['通讯配置'] = '''
1、打开通讯配置界面
2、通信参数:
    (1)通讯端口1:用于传输指令或参数的端口
    (2)通讯端口2:用于传输波形数据的端口
    (3)TCP/IP地址:下位机的IP地址
    (4)子网掩码: 无用作为保留
    (5)网关: 无用作为保留
3、测试按钮: 可以测试连接是否正常，如果遇到连接失败问题，可以尝试将电脑网口的IP和网关设置与下位机地址在同一局域网内
4、保存按钮: 可以直接将参数保存，或在测试成功后直接保存
                '''
        self.help_dict_str['重置TCP连接'] = '''
1、当下位机TCP通讯端口不小心失态(进入未知的通讯状态)时，需要重置一下TCP网络，可以通过RS232模块与下位机通信重启TCP通信
2、打开重置TCP连接页面
3、连接好下位机与PC机之间的232通信链路，并获取可用串口号
4、选择适当的可用串口号，并输入16位16进制通信控制密码，然后打开串口
5、如果打开串口成功，串口状态灯将变为绿色，'重置下位机TCP通信'按钮将变为可用
6、点击'重置下位机TCP通信'按钮，等待重置成功提示即可关闭串口或直接退出，如遇失败请检查后重试
                '''
        self.help_dict_str['远程升级'] = '''
1、通过TCP或SCI对芯片程序进行升级
2、会根据CPU1和CPU2的单选框对下位机进行烧写
3、烧写之前会自动发送复位芯片进入botloader系统，（TCP发送和SCI发送),如果程序烧写失败会一直在bootloader系统当中循环等待烧写，所以有时需要先上线再烧写，有时不需要，这个需要特别注意一下
4、烧写所需的hex文件是CCS在编译时自动生成的.hex文件
                '''
        self.help_dict_str['上线'] = '''
1、将上位机与下位机的'指令通讯端口'进行连接
2、成功连接后将持续刷新tab栏展示的界面所有参数和控制台所有的参数
3、成功连接后将持续接收上位机的动作指令并发送给下位机
4、只有成功连接后才能连接'波形数据通信端口'并开始传输波形数据
                '''
        self.help_dict_str['下线'] = '''
断开与下位机的TCP连接
                '''
        self.help_dict_str['保存host'] = '''
1、启动'保存host'按钮，将会持续保存配置文件内'日志输出'为'1'的参数值
2、结束后将会以启动时间命名的日志文件保存到当前目录下
                '''
        self.help_dict_str['打开'] = '''
1、打开scope波形页面(有5种界面):
    (1)X1   1X1的画面
    (2)X2   1X2的画面
    (3)X3   1X3的画面  
    (4)X4   2X2的画面
    (5)X6   2X3的画面
2、'波形端口'有两种连接方式
    (1)指令端口连接时打开视图窗口会触发连接
    (2)指令端口未连接时打开视图窗口之后再连接指令端口时
3、在点击'开始'按钮接收波形数据之前，可以设置显示波形的设置:
    整体:
    (1)刷新频率: 调整界面的刷新帧率
    (2)开始/结束: 开始/结束波形数据的接收
    (3)开始截取数据/数据保存中: 开始/结束波形数据的记录生成h5文件
    
    单个画面:
    (1)采样间隔: 每隔多少个数据点采取一个样本用于显示在波形图上面
    (2)采样个数: 一共采集多少个点位用于图形显示是哪个面，(目前最大支持10000)
    (3)显示时间: 通过前两项自动计算图形显示的时长(0.1ms * 采样间隔 * 采样个数)
    (4)通道选择: 选择单个页面显示波形的通道(目前最大支持7个通道同时显示)
    (5)取消全部选择: 用以快速清除对通道的勾选
    (6)暂停: 用以暂停单个页面的刷新，当取消暂停时页面会跳过后续的刷新直接追上当前时间的刷新
                        '''
        self.help_dict_str['通道管理'] = '''
1、打开通道管理页面
2、页面控制属性:
    (1)通道号: 目前最大支持40个通道， 当勾选上时将会出现在波形视图的复选框里，且保存数据的通道也是保存勾选上的通道
    (2)通道名称: 为通道起个别名，方便观察和记录
    (3)通道数量: 目前只支持偶数通道个数2-40个，用于设置上位机与下位机通信波形数据是传递通道的数量，可以有效控制传输带宽
                        '''
        self.help_dict_str['转换波形数据'] = '''
1、在波形页面当中生成的保存数据为h5文件不能直接查看，可用过此功能将h5文件转换为CSV文件，便于查看
2、此功能会造成页面卡顿，不建议在传输波形数据时进行转换
                        '''
        self.help_dict_str['E2PROM'] = '''
1、打开E2PROM参数表页面
2、此表格用于展示可以单独固化到E2PROM当中的变量，同TABLE表格当中的数据一样可以查看，可以修改
3、功能按钮:
    (1)加载参数: 将配置文件的缺省值加载到参数的当前值，并传入下位机
    (2)读取参数: 将E2PROM的值读出来写入当前值，并传回上位机显示
    (3)保存参数: 将当前值保存到配置文件的缺省值当中(如果保存当中出现错误，大概率是文件已被其他应用打开了)
    (4)固化参数: 将当前值写入E2PROM当中
                        '''
        self.help_dict_str['帮助'] = '''
显示关于上位机的使用说明文档
                        '''
        self.help_dict_str['参数配置'] = '''
1、通过对配置文件的'类型号'、'1级类型'和'2级类型'对参数进行分类，分页面处理
2、通过单击结构树的子节点可生成dock(right)临时查看table的界面
3、通过快速双击结构树的子节点可生成主界面的常驻table界面
                        '''
        self.help_dict_str['Tab栏'] = '''
1、点击结构树生成table界面时同时会生成tab栏
2、点击Tab栏条目可对显示的Table页面进行切换或关闭
                        '''
        self.help_dict_str['控制台'] = '''
1、通过对参数表操作添加相应参数的'快捷控件'到控制台:
    (1)快双击参数表的'参数名称'一列，添加顺序为(1-按钮 2-下拉列表 3-输入列表)按可添加的顺序优先级添加
    (2)鼠标右键单击生成菜单，将会显示此参数可添加的控件，鼠标左键单击选择添加控件
2、已添加的控件会自动保存记录下次打开时将会自动添加，如果添加失败则会跳过部分控件
3、只读的控件优先级更高，会显示最上方
                        '''
        self.help_dict_str['按钮'] = '''
1、按钮分为三种:
    (1)'数据类型'为'5'的按钮，可同时点亮一个或多个状态会生成对应的位数据传递给下位机
    (2)'数据类型'为'3'的按钮，如果'选择型操作定义'带有'禁止'、'off'和'no'字样的，将会少一个对应的开关，将其他状态按组添加到控制台
    (3)'数据类型'为'3'的按钮，没有上述情况将会按'选择型操作定义'全部按组添加到控制到
                        '''
        self.help_dict_str['下拉列表'] = '''
所有'数据类型'为'3'的参数都可以添加到下拉列表
                        '''
        self.help_dict_str['输入列表'] = '''
1、所有'数据类型'不为'5'和'3'的数据都会添加到输入列表
2、如果'数据类型'为'3'为'5'的情况下，如果'选择型操作定义'没有匹配内容，也将会被定义为纯数字输入
                        '''
        self.help_dict_str['临时状态'] = '''
1、连接状态: 实时显示TCP端口1的连接状态
    (1)绿色: 已连接
    (2)红色: 未连接
                        '''
        self.help_dict_str['固定状态'] = '''
显示向下位机写入数据的反馈
                        '''
        self.help_dict_str[''] = '''
                        '''
        self.help_dict_str[''] = '''
                        '''
        self.help_dict_str[''] = '''
                        '''


    def tree_clicked(self):
        item = self.tree_view.currentItem()
        str_n = item.text(0)
        if str_n in self.help_dict_str:
            self.text_edit.setPlainText(self.help_dict_str[str_n])


if __name__ == "__main__":
    app = QApplication(sys.argv)
    myWin = Help_Window()
    myWin.show()
    sys.exit(app.exec_())
